package com.momo.service.sysmain;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.momo.common.common.DateUtils;
import com.momo.common.common.JSONResult;
import com.momo.common.error.RedisKeyEnum;
import com.momo.common.req.sysmain.LoginUserReq;
import com.momo.common.req.sysmain.RedisUser;
import com.momo.common.res.sysmain.ResPonseUser;
import com.momo.common.util.Encrypt;
import com.momo.common.util.JwtTokenUtil;
import com.momo.common.util.RedisUtil;
import com.momo.common.util.StrUtil;
import com.momo.common.util.verificationCode.captcha.SpecCaptcha;
import com.momo.mapper.dao.UserGroupDAO;
import com.momo.mapper.dataobject.LoginLogDO;
import com.momo.mapper.dataobject.RoleDO;
import com.momo.mapper.dataobject.UserDO;
import com.momo.mapper.dataobject.UserGroupDO;
import com.momo.mapper.mapper.sysSetting.RoleMapper;
import com.momo.mapper.mapper.sysmain.SysUserMapper;
import com.momo.service.async.LoginLogAsync;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;

/**
 * Created by MOMO on 2019/1/31.
 * 系统入口
 */
@Service
@Slf4j
public class SystemMainService {
    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private UserGroupDAO userGroupDAO;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    @Autowired
    private LoginLogAsync loginLogAsync;
    @Autowired
    private RoleMapper roleMapper;

    /**
     * 用户登录
     *
     * @param loginUserReq
     * @return
     */
    public JSONResult userLogin(LoginUserReq loginUserReq, HttpServletRequest request) {
        //todo 验证码
        /*JSONResult jsonResult = checkVerificationCode(loginReq);
        if (jsonResult.isOK()) {
            return jsonResult;
        }*/

        UserDO userDO = sysUserMapper.userLogin(loginUserReq.getSysUserLoginName());
        if (null == userDO) {
            return JSONResult.errorMap("登录名不存在");
        }
        //剔除超级管理员限制
        if (!userDO.getId().equals(1L)) {
            if ("1".equals(userDO.getDelFlag())) {
                return JSONResult.errorMap("您的账户已被删除，请联系管理员");
            }
            if ("1".equals(userDO.getIsForbidden())) {
                return JSONResult.errorMap("您的账户已被禁用，请联系管理员");
            }
        }
        String pwd = Encrypt.getShiroPassword(loginUserReq.getSysUserPwd(), userDO.getSysUserAuthSalt(), 2);
        if (!userDO.getSysUserPwd().equals(pwd)) {
            return JSONResult.errorMap("用户名或者密码错误");
        }
        //剔除超级管理员限制
        if (!userDO.getId().equals(1L)) {
            UserGroupDO userGroupDO = userGroupDAO.getUserGroupById(userDO.getGroupId());
            if (null == userGroupDO) {
                return JSONResult.errorMap("您所在的用户组不存在");
            }
            if ("1".equals(userGroupDO.getUserGroupStatus())) {
                return JSONResult.errorMap("您所在的用户组已被禁用");
            }
            if ("1".equals(userGroupDO.getDelFlag())) {
                return JSONResult.errorMap("您所在的用户组已被删除");
            }
            if (1 != userGroupDO.getId() && DateUtils.timeDifference(userGroupDO.getSysAccountEndTime())) {
                return JSONResult.errorMap("您所在的用户组时间已到期,请续约后在次登录");
            }
        }
        String redisUserKey = StrUtil.genUUID();
        RedisUser redisUser = RedisUser.builder().redisUserKey(redisUserKey)
                .sysUserLoginName(userDO.getSysUserLoginName()).sysUserPhone(userDO.getSysUserPhone())
                .deptId(userDO.getDeptId()).groupId(userDO.getGroupId()).id(userDO.getId())
                .sysLoginNumber(userDO.getSysLoginNumber()).sysUserName(userDO.getSysUserName()).build();
        List<RoleDO> roleDOS = roleMapper.getRolesByUserId(userDO.getId());
        roleDOS.forEach(roleDO -> {
            if ("0".equals(roleDO.getSysRoleType())) {
                //此处校验当前登录用户是否是管理员
                redisUser.setAdminRole(true);
                redisUser.setAdminRoleId(roleDO.getId());
            }
        });
        String jsonStr = JSONObject.toJSONString(redisUser);
        //生成token
        // randomKey和token已经生成完毕
        final String randomKey = jwtTokenUtil.getRandomKey();
        final String token = jwtTokenUtil.generateToken(jsonStr, randomKey);
        //限制登录次数 -1 则不进行限制
        Integer loginNumber = userDO.getSysLoginNumber();
        //限制登录次数
        if (loginNumber != -1) {
            //redis  key--》用户id     v----》 List<String> String=uuid
            //redis  key--》uuid     v----》 token
            Object listUuid = redisUtil.get(RedisKeyEnum.REDIS_KEY_USER_ID.getKey() + userDO.getId());
            //首次登录
            if (listUuid == null) {
                List<String> list = Lists.newArrayList();
                list.add(redisUserKey);
                String listStr = JSONObject.toJSONString(list);
                //redis  key--》用户id     v----》 List<String> String=uuid
                loginNumber(userDO.getId(), listStr, redisUserKey, token);
            } else {//已经登录过了
                List<String> list = JSON.parseObject((String) listUuid, new TypeReference<List<String>>() {
                });
                //登录次数已满，需要剔除最先登录的用户
                if (list.size() >= loginNumber) {
                    String firstUuid = list.get(0);
                    redisUtil.del(RedisKeyEnum.REDIS_KEY_USER_INFO.getKey() + firstUuid);
                    list.remove(0);
                    list.add(redisUserKey);
                    String listStr = JSONObject.toJSONString(list);
                    loginNumber(userDO.getId(), listStr, redisUserKey, token);
                } else {//登录次数未满
                    list.add(redisUserKey);
                    String listStr = JSONObject.toJSONString(list);
                    loginNumber(userDO.getId(), listStr, redisUserKey, token);
                }
            }
        } else if (loginNumber.equals(-1)) {//不限制登录次数
            //token放入 redis
            redisUtil.set(RedisKeyEnum.REDIS_KEY_USER_INFO.getKey() + redisUserKey, token, RedisKeyEnum.REDIS_KEY_USER_INFO.getExpireTime());
        }
        ResPonseUser resPonseUser = new ResPonseUser();
        resPonseUser.setGroupId(userDO.getGroupId());
        resPonseUser.setSysUserEmail(userDO.getSysUserEmail());
        resPonseUser.setSysUserName(userDO.getSysUserName());
        resPonseUser.setSysUserPhone(userDO.getSysUserPhone());
        resPonseUser.setAccess_token(redisUserKey);

        LoginLogDO entity = new LoginLogDO();
        entity.setGroupId(resPonseUser.getGroupId());
        entity.setUserLoginName(userDO.getSysUserLoginName());
        entity.setUserUserName(userDO.getSysUserName());
        entity.setUserId(userDO.getId());
        loginLogAsync.loginLog(entity, request);
        return JSONResult.ok(resPonseUser);
    }

    /**
     * @param userId   用户id
     * @param listUuid List<String> String=uuid
     * @param uuid
     * @param token
     */
    private void loginNumber(Long userId, String listUuid, String uuid, String token) {
        //redis  key--》用户id     v----》 List<String> String=uuid
        redisUtil.set(RedisKeyEnum.REDIS_KEY_USER_ID.getKey() + userId, listUuid, RedisKeyEnum.REDIS_KEY_USER_ID.getExpireTime());
        redisUtil.set(RedisKeyEnum.REDIS_KEY_USER_INFO.getKey() + uuid, token, RedisKeyEnum.REDIS_KEY_USER_INFO.getExpireTime());
    }

    public JSONResult createVerificationCode() {
        try {
            SpecCaptcha specCaptcha = new SpecCaptcha();
            String verUUidCode = specCaptcha.outaaaa(null);
            String key = StrUtil.genUUID();
            String verificationCode = specCaptcha.text();
            redisUtil.set(RedisKeyEnum.REDIS_KEY_IMG_UUID_CODE.getKey() + key, verificationCode, RedisKeyEnum.REDIS_KEY_IMG_UUID_CODE.getExpireTime());
            Map<String, Object> map = Maps.newHashMap();
            //base64
            map.put(RedisKeyEnum.REDIS_KEY_IMG_BASE.getKey(), verUUidCode);
            //一个verUUidCode对应当前请求用户
            map.put(RedisKeyEnum.REDIS_KEY_IMG_UUID_CODE_HEADER.getKey(), key);
            map.put(RedisKeyEnum.REDIS_KEY_IMG_TYPE.getKey(), "data:image/png;base64,");
            return JSONResult.ok(map);
        } catch (Exception e) {
            log.error("生成验证码异常:{},{}", e.getMessage(), e.toString());
            return JSONResult.errorMap("获取验证码base64异常");
        }
    }

    public JSONResult checkVerificationCode(LoginUserReq loginReq) {
        String key = "verUUidCode:" + loginReq.getVerUUidCode();
        boolean existsKey = redisUtil.hasKey(key);
        if (!existsKey) {//验证验证码
            return JSONResult.errorMap("验证码已失效");
        }
        String verUUidCode = (String) redisUtil.get(key);
        String aa = loginReq.getVerificationCode().toLowerCase().trim();
        if (!aa.equals(verUUidCode.toLowerCase().trim())) {
            return JSONResult.errorMap("验证码不正确");
        }
        return JSONResult.ok();
    }
}
